import queue
import threading
import time
import tkinter as tk
from tkinter import messagebox

import serial
import serial.tools.list_ports
import ttkbootstrap as ttkb
from ttkbootstrap.constants import *

from app.util.annotation_util import annotate, ClassInfo
from app.view.base_view import View


@annotate(ClassInfo(name="FtSerialParam", category="ft_tool"))
class FtSerialParamSetlView(View):
    """设置视图"""

    def __init__(self, parent, controller):
        super().__init__(parent, controller)
        # 串口相关变量
        self.serial_port = None
        self.is_connected = False
        self.ports = []
        self.baud_rates = [9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600]

        # 参数数据
        self.parameters = [
            {"name": "设备名称", "key": "NAME", "value": "", "description": "设备的名称标识", "default": "Device-XXX"},
            {"name": "序列号", "key": "SN", "value": "", "description": "设备唯一序列号", "default": "SN12345678"},
            {"name": "硬件版本", "key": "HW_VERSION", "value": "", "description": "硬件版本号", "default": "V1.0"},
            {"name": "软件版本", "key": "SW_VERSION", "value": "", "description": "软件版本号", "default": "V1.0.0"},
            {"name": "MAC地址", "key": "MAC", "value": "", "description": "网络物理地址",
             "default": "00:1A:2B:3C:4D:5E"},
            {"name": "IP地址", "key": "IP", "value": "", "description": "网络IP地址", "default": "192.168.1.100"},
            {"name": "波特率", "key": "BAUDRATE", "value": "", "description": "串口波特率", "default": "115200"},
            {"name": "设备型号", "key": "MODEL", "value": "", "description": "设备型号", "default": "Model-A"}
        ]

        # 存储按钮的字典
        self.action_buttons = {}

        # 消息队列用于线程间通信
        self.msg_queue = queue.Queue()

        # 创建UI
        self._create_widgets()

        # 启动消息处理线程
        self.start_message_thread()

        # 初始搜索串口
        self.search_ports()

    def _create_widgets(self):
        # 创建主框架
        main_frame = ttkb.Frame(self, padding=10)
        main_frame.pack(fill=BOTH, expand=True)

        # 顶部串口控制区域
        serial_frame = ttkb.LabelFrame(main_frame, text="串口控制", padding=10)
        serial_frame.pack(fill=X, pady=(0, 10))

        # 串口设置
        port_frame = ttkb.Frame(serial_frame)
        port_frame.pack(fill=X)

        ttkb.Label(port_frame, text="串口:").grid(row=0, column=0, padx=5, pady=5, sticky=W)
        self.port_var = tk.StringVar()
        self.port_combobox = ttkb.Combobox(
            port_frame,
            textvariable=self.port_var,
            state="readonly",
            width=15
        )
        self.port_combobox.grid(row=0, column=1, padx=5, pady=5)

        ttkb.Label(port_frame, text="波特率:").grid(row=0, column=2, padx=5, pady=5, sticky=W)
        self.baud_var = tk.IntVar(value=115200)
        self.baud_combobox = ttkb.Combobox(
            port_frame,
            textvariable=self.baud_var,
            values=self.baud_rates,
            state="readonly",
            width=10
        )
        self.baud_combobox.grid(row=0, column=3, padx=5, pady=5)

        ttkb.Button(port_frame, text="搜索串口", command=self.search_ports, bootstyle=OUTLINE).grid(
            row=0, column=4, padx=5, pady=5)
        self.connect_btn = ttkb.Button(
            port_frame,
            text="打开串口",
            command=self.toggle_connection,
            bootstyle=SUCCESS
        )
        self.connect_btn.grid(row=0, column=5, padx=5, pady=5)

        # 操作按钮
        action_frame = ttkb.Frame(serial_frame)
        action_frame.pack(fill=X, pady=10)

        self.auto_get_btn = ttkb.Button(
            action_frame,
            text="自动获取所有参数",
            command=self.auto_get_parameters,
            bootstyle=PRIMARY,
            state=DISABLED
        )
        self.auto_get_btn.pack(side=LEFT, padx=5)

        self.clear_btn = ttkb.Button(
            action_frame,
            text="清除显示参数",
            command=self.clear_parameters,
            bootstyle=OUTLINE
        )
        self.clear_btn.pack(side=LEFT, padx=5)

        # 参数表格区域
        table_frame = ttkb.LabelFrame(main_frame, text="设备参数", padding=10)
        table_frame.pack(fill=BOTH, expand=True)

        # 创建表格
        columns = ("name", "value", "description", "action")
        self.param_tree = ttkb.Treeview(
            table_frame,
            columns=columns,
            show="headings",
            height=10
        )

        # 设置列标题和宽度
        self.param_tree.heading("name", text="名称")
        self.param_tree.heading("value", text="值")
        self.param_tree.heading("description", text="说明")
        self.param_tree.heading("action", text="操作")

        self.param_tree.column("name", width=120, anchor=W)
        self.param_tree.column("value", width=180, anchor=W)
        self.param_tree.column("description", width=200, anchor=W)
        self.param_tree.column("action", width=250, anchor=CENTER)

        # 添加滚动条
        scrollbar = ttkb.Scrollbar(table_frame, orient="vertical", command=self.param_tree.yview)
        self.param_tree.configure(yscrollcommand=scrollbar.set)

        scrollbar.pack(side=RIGHT, fill=Y)
        self.param_tree.pack(fill=BOTH, expand=True)

        # 绑定事件，当表格滚动或大小改变时重新定位按钮
        self.param_tree.bind("<Configure>", self.update_buttons_position)
        # self.param_tree.bind("<TreeviewScroll>", self.update_buttons_position)

        # 填充参数表格
        self.populate_parameter_table()

        # 状态栏
        self.status_var = tk.StringVar(value="就绪")
        self.status_bar = ttkb.Label(self, textvariable=self.status_var, anchor=W)
        self.status_bar.pack(side=BOTTOM, fill=X)

    def start_message_thread(self):
        """启动消息处理线程"""
        self.running = True
        threading.Thread(target=self.process_messages, daemon=True).start()

    def process_messages(self):
        """处理消息队列中的消息"""
        while self.running:
            try:
                msg = self.msg_queue.get(timeout=0.1)
                self.status_var.set(msg)
                self.msg_queue.task_done()
            except queue.Empty:
                continue

    def log(self, message):
        """记录日志消息"""
        self.msg_queue.put(message)

    def populate_parameter_table(self):
        """填充参数表格"""
        # 清除之前的按钮
        for btn in self.action_buttons.values():
            for b in btn:
                b.destroy()
        self.action_buttons.clear()

        # 清空现有项
        for item in self.param_tree.get_children():
            self.param_tree.delete(item)

        # 添加参数
        for i, param in enumerate(self.parameters):
            # 将参数添加到表格
            item = self.param_tree.insert("", tk.END, values=(
                param["name"],
                param["value"],
                param["description"],
                "操作区"  # 占位
            ))

            # 创建按钮列表
            buttons = []

            # 操作按钮
            action_btn = ttkb.Button(
                self.param_tree,
                text="操作",
                command=lambda p=param: self.show_param_action(p),
                bootstyle=OUTLINE,
                width=6
            )
            buttons.append(action_btn)

            # 获取按钮
            get_btn = ttkb.Button(
                self.param_tree,
                text="获取",
                command=lambda p=param: self.get_parameter(p),
                bootstyle=INFO,
                width=6,
                state=DISABLED if not self.is_connected else NORMAL
            )
            buttons.append(get_btn)

            # 写入按钮
            write_btn = ttkb.Button(
                self.param_tree,
                text="写入",
                command=lambda p=param: self.write_parameter(p),
                bootstyle=SUCCESS,
                width=6,
                state=DISABLED if not self.is_connected else NORMAL
            )
            buttons.append(write_btn)

            # 默认按钮
            default_btn = ttkb.Button(
                self.param_tree,
                text="默认",
                command=lambda p=param: self.set_default_value(p),
                bootstyle=WARNING,
                width=6
            )
            buttons.append(default_btn)

            # 存储按钮引用
            self.action_buttons[item] = buttons

        # 定位按钮
        self.update_buttons_position()

    def update_buttons_position(self, event=None):
        """更新按钮位置以确保它们显示在正确的单元格中"""
        # for item, buttons in self.action_buttons.items():
        #     # 获取单元格坐标
        #     x, y, width, height = self.param_tree.bbox(item, "action")
        #
        #     # 计算每个按钮的位置
        #     btn_width = width // len(buttons) - 4
        #     for i, btn in enumerate(buttons):
        #         btn.place(x=x + i * btn_width + 2, y=y + 1, width=btn_width, height=height - 2)
        pass

    def update_parameter_value(self, param_key, new_value):
        """更新参数值并刷新表格"""
        for param in self.parameters:
            if param["key"] == param_key:
                param["value"] = new_value
                break

        # 刷新表格
        self.populate_parameter_table()

    def search_ports(self):
        """搜索可用串口"""
        self.log("正在搜索串口...")
        self.ports = []
        ports = serial.tools.list_ports.comports()
        for port in ports:
            self.ports.append(port.device)

        self.port_combobox['values'] = self.ports
        if self.ports:
            self.port_combobox.current(0)
            self.log(f"找到 {len(self.ports)} 个串口")
        else:
            self.log("未找到可用串口")

    def toggle_connection(self):
        """切换串口连接状态"""
        if self.is_connected:
            self.close_port()
        else:
            self.open_port()

    def open_port(self):
        """打开串口"""
        try:
            port = self.port_var.get()
            baud = self.baud_var.get()

            if not port:
                messagebox.showerror("错误", "请选择串口")
                return

            self.serial_port = serial.Serial(
                port=port,
                baudrate=baud,
                timeout=1,
                write_timeout=1
            )

            if self.serial_port.is_open:
                self.is_connected = True
                self.connect_btn.config(text="关闭串口", bootstyle=DANGER)
                self.auto_get_btn.config(state=NORMAL)
                self.log(f"已打开串口 {port}，波特率 {baud}")

                # 启动串口监听线程
                threading.Thread(target=self.read_serial, daemon=True).start()

                # 刷新参数表格以启用按钮
                self.populate_parameter_table()
        except Exception as e:
            self.log(f"打开串口失败: {str(e)}")
            messagebox.showerror("错误", f"打开串口失败: {str(e)}")

    def close_port(self):
        """关闭串口"""
        try:
            if self.serial_port and self.serial_port.is_open:
                self.serial_port.close()

            self.is_connected = False
            self.connect_btn.config(text="打开串口", bootstyle=SUCCESS)
            self.auto_get_btn.config(state=DISABLED)
            self.log("串口已关闭")

            # 刷新参数表格以禁用按钮
            self.populate_parameter_table()
        except Exception as e:
            self.log(f"关闭串口失败: {str(e)}")

    def read_serial(self):
        """读取串口数据的线程函数"""
        while self.is_connected and self.serial_port.is_open:
            try:
                if self.serial_port.in_waiting > 0:
                    data = self.serial_port.read_all()
                    try:
                        response = data.decode('utf-8', errors='replace').strip()
                        self.process_response(response)
                        self.log(f"收到数据: {response}")
                    except:
                        self.log(f"收到二进制数据: {len(data)} 字节")

                time.sleep(0.01)
            except Exception as e:
                if self.is_connected:  # 只有在连接状态下的错误才报告
                    self.log(f"串口读取错误: {str(e)}")
                break

    def send_command(self, command):
        """发送命令到串口"""
        if not self.is_connected or not self.serial_port or not self.serial_port.is_open:
            return False

        try:
            self.serial_port.write((command + "\r\n").encode('utf-8'))
            self.log(f"发送命令: {command}")
            return True
        except Exception as e:
            self.log(f"发送命令失败: {str(e)}")
            return False

    def process_response(self, response):
        """处理串口响应数据"""
        # 解析形如 "KEY=VALUE" 的响应
        if "=" in response:
            parts = response.split("=", 1)
            if len(parts) == 2:
                key, value = parts[0].strip(), parts[1].strip()
                self.update_parameter_value(key, value)

    def get_parameter(self, param):
        """获取单个参数"""
        if not self.is_connected:
            messagebox.showwarning("警告", "请先打开串口")
            return

        # 发送获取参数命令，格式：GET_KEY
        command = f"GET_{param['key']}"
        self.send_command(command)
        self.log(f"正在获取 {param['name']}...")

    def write_parameter(self, param):
        """写入单个参数"""
        if not self.is_connected:
            messagebox.showwarning("警告", "请先打开串口")
            return

        # 获取当前表格中的值
        # 查找参数在表格中的位置
        for item in self.param_tree.get_children():
            values = self.param_tree.item(item, "values")
            if values[0] == param["name"]:
                new_value = values[1]
                break
        else:
            messagebox.showerror("错误", "未找到参数")
            return

        if not new_value:
            messagebox.showwarning("警告", "参数值不能为空")
            return

        # 发送设置参数命令，格式：SET_KEY=VALUE
        command = f"SET_{param['key']}={new_value}"
        self.send_command(command)
        self.log(f"正在设置 {param['name']} 为 {new_value}...")

        # 延迟后重新获取参数以确认
        threading.Timer(1.0, self.get_parameter, args=(param,)).start()

    def set_default_value(self, param):
        """设置参数默认值（仅在界面上，不发送到设备）"""
        # 更新参数值
        param["value"] = param["default"]
        # 刷新表格
        self.populate_parameter_table()
        self.log(f"已设置 {param['name']} 为默认值")

    def auto_get_parameters(self):
        """自动获取所有参数"""
        if not self.is_connected:
            messagebox.showwarning("警告", "请先打开串口")
            return

        self.log("开始自动获取所有参数...")

        # 发送获取所有参数的命令
        self.send_command("GET_ALL")

        # 对于不支持批量获取的设备，可以逐个获取
        # threading.Thread(target=self.get_all_parameters_one_by_one, daemon=True).start()

    def get_all_parameters_one_by_one(self):
        """逐个获取所有参数（用于不支持批量获取的设备）"""
        for param in self.parameters:
            if not self.is_connected:  # 检查是否已断开连接
                break

            self.get_parameter(param)
            time.sleep(0.5)  # 等待响应

        if self.is_connected:
            self.log("所有参数获取完成")

    def clear_parameters(self):
        """清除所有参数显示值"""
        for param in self.parameters:
            param["value"] = ""

        # 刷新表格
        self.populate_parameter_table()
        self.log("已清除所有参数显示值")

    def show_param_action(self, param):
        """显示参数操作对话框"""
        dialog = ttkb.Toplevel(self)
        dialog.title(f"{param['name']} 操作")
        dialog.geometry("400x300")
        dialog.transient(self)
        dialog.grab_set()

        # 参数信息
        frame = ttkb.Frame(dialog, padding=10)
        frame.pack(fill=BOTH, expand=True)

        ttkb.Label(frame, text=f"参数名称: {param['name']}", font=("Arial", 10, "bold")).pack(anchor=W, pady=5)
        ttkb.Label(frame, text=f"参数标识: {param['key']}").pack(anchor=W, pady=2)
        ttkb.Label(frame, text=f"当前值: {param['value']}").pack(anchor=W, pady=2)
        ttkb.Label(frame, text=f"默认值: {param['default']}").pack(anchor=W, pady=2)
        ttkb.Label(frame, text=f"说明: {param['description']}").pack(anchor=W, pady=2)

        # 新值输入
        ttkb.Label(frame, text="新值:").pack(anchor=W, pady=(10, 2))
        new_value_var = tk.StringVar(value=param["value"])
        ttkb.Entry(frame, textvariable=new_value_var).pack(fill=X, pady=2)

        # 按钮
        btn_frame = ttkb.Frame(frame)
        btn_frame.pack(fill=X, pady=10)

        ttkb.Button(
            btn_frame,
            text="获取参数",
            command=lambda: [self.get_parameter(param), dialog.destroy()],
            bootstyle=INFO
        ).pack(side=LEFT, padx=5)

        ttkb.Button(
            btn_frame,
            text="设置参数",
            command=lambda: [
                param.update({"value": new_value_var.get()}),
                self.populate_parameter_table(),
                self.write_parameter(param),
                dialog.destroy()
            ],
            bootstyle=SUCCESS
        ).pack(side=LEFT, padx=5)

        ttkb.Button(
            btn_frame,
            text="恢复默认",
            command=lambda: [
                param.update({"value": param["default"]}),
                self.populate_parameter_table(),
                dialog.destroy()
            ],
            bootstyle=WARNING
        ).pack(side=LEFT, padx=5)

        ttkb.Button(
            btn_frame,
            text="取消",
            command=dialog.destroy,
            bootstyle=OUTLINE
        ).pack(side=LEFT, padx=5)

    def on_close(self):
        """窗口关闭时的处理"""
        self.running = False
        self.close_port()
        self.destroy()

    def create_widgets(self):
        pass
